package com.netx.generics.io;
import java.io.IOException;
import java.net.URI;
import java.net.URL;

import com.netx.generics.basic.Checker;
import com.netx.generics.time.Moment;


abstract class FileObjectImpl implements FileObject {

	protected final FileSystem fs;
	protected final ProtocolImpl provider;

	protected FileObjectImpl(FileSystem fs, ProtocolImpl provider) {
		this.fs = fs;
		this.provider = provider;
	}
	
	public FileSystem getFileSystem() {
		return fs;
	}

	public String getName() {
		return provider.getName();
	}

	public boolean equals(Object obj) {
		return compareTo(obj) == 0;
	}

	public String getPath() {
		return provider.getPath();
	}

	public String getPhysicalPath() {
		return provider.getPhysicalPath();
	}

	// TODO this doesn't work on network filesystems
	// (it returns true, even if you don't have permissions
	// to write)
	public boolean canWrite() throws IOException {
		try {
			return provider.canWrite();
		}
		catch(IOException io) {
			throw provider.translate(io, getPath());
		}
		catch(RuntimeException re) {
			throw provider.translate(re, getPath());
		}
	}

	public boolean isHidden() throws IOException {
		try {
			return provider.isHidden();
		}
		catch(IOException io) {
			throw provider.translate(io, getPath());
		}
		catch(RuntimeException re) {
			throw provider.translate(re, getPath());
		}
	}
	
	public boolean isReadOnly() throws IOException {
		try {
			if(provider.canRead() && !provider.canWrite()) {
				return true;
			}
			else {
				return false;
			}
		}
		catch(IOException io) {
			throw provider.translate(io, getPath());
		}
		catch(RuntimeException re) {
			throw provider.translate(re, getPath());
		}
	}

	public void makeReadOnly() throws IOException {
		try {
			provider.setReadOnly();
		}
		catch(IOException io) {
			throw provider.translate(io, getPath());
		}
		catch(RuntimeException re) {
			throw provider.translate(re, getPath());
		}
	}

	public Moment getLastModified() throws IOException {
		try {
			return provider.getLastModified();
		}
		catch(IOException io) {
			throw provider.translate(io, getPath());
		}
		catch(RuntimeException re) {
			throw provider.translate(re, getPath());
		}
	}
	
	public void setLastModified(Moment lastModified) throws IOException {
		Checker.checkNull(lastModified, "lastModified");
		try {
			provider.setLastModified(lastModified);
		}
		catch(IOException io) {
			throw provider.translate(io, getPath());
		}
		catch(RuntimeException re) {
			throw provider.translate(re, getPath());
		}
	}
	
	public Directory getParent() {
		return new DirectoryImpl(getFileSystem(), provider.getChild(".."));
	}

	public boolean delete() throws IOException {
		try {
			//TODO should this return boolean?
			// Empirical: if you dont have permissions to write to the dir,
			// no SecurityException is thrown; instead, the file doesnt get
			// deleted and this method returns false.
			// We probably want to throw an AccessDeniedException instead.
			return provider.delete();
		}
		catch(IOException io) {
			throw provider.translate(io, getPath());
		}
		catch(RuntimeException re) {
			throw provider.translate(re, getPath());
		}
	}

	public void deleteOnExit() throws IOException {
		try {
			provider.deleteOnExit();
		}
		catch(IOException io) {
			throw provider.translate(io, getPath());
		}
		catch(RuntimeException re) {
			throw provider.translate(re, getPath());
		}
	}

	public void renameTo(String name) throws IOException {
		Checker.checkEmpty(name, "name");
		try {
			provider.renameTo(name);
		}
		catch(IOException io) {
			throw provider.translate(io, getPath());
		}
		catch(RuntimeException re) {
			throw provider.translate(re, getPath());
		}
	}

	public void copyTo(Directory dir) throws IOException {
		copyTo(dir, getName());
	}

	public URI toURI() {
		return provider.toURI();
	}

	public URL toURL() {
		return provider.toURL();
	}

	public String toString() {
		return getName();
	}
}
